#include "i2c_AT24CXX.h"

extern int simu_flag;

//初始化IIC接口
void AT24CXX_Init(void)
{
	gpio_iof_config(GPIOA, IOF_I2C_MASK);
    i2c_setup(I2C0, 0xC8, I2C_CTR_EN);//100M->100K
}

//在AT24CXX指定地址读出一个字节的数据
//ReadAddr:开始读数的地址  
//返回值  :读到的数据
U8 AT24CXX_ReadOneByte(U16 ReadAddr)
{
    U8 value = 0;

    if(ReadAddr>EE_TYPE)//数据范围检测
        return 0;
    
    do {
        i2c_send_data(I2C0, 0xA0);
        i2c_send_command(I2C0, I2C_START_WRITE);
    } while (!i2c_get_ack(I2C0));

    if(EE_TYPE>AT24C16)
	{
		// Send Write Address High 8 bit
        i2c_send_data(I2C0, (U8)(ReadAddr>>8)); //Addr High
        i2c_send_command(I2C0, I2C_WRITE); //send data
        if(!i2c_get_ack(I2C0)) {
            printf("No ack received from EEPROM, Address High\n");
            return 0;
        }
	}

    // Send Write Address Low 8 bit
    i2c_send_data(I2C0, (U8)(ReadAddr&0xff)); //Addr Low
    i2c_send_command(I2C0, I2C_WRITE); //send data
    if(!i2c_get_ack(I2C0)) {
        printf("No ack received from EEPROM, Address Low\n");
        return 0;
    }

    // Send Control Byte
    i2c_send_data(I2C0, 0xA1); // Control Byte: 0xA0
    i2c_send_command(I2C0, I2C_START_WRITE); //do a start bit and send data
    if(!i2c_get_ack(I2C0)) {
        printf("No ack received from EEPROM, Device Control, Read data\n");
        return 0;
    }

    // Read Data
    i2c_send_command(I2C0, I2C_STOP_READ|I2C_SEND_NACK); //read data, send NACK and do a stop bit
    while(i2c_busy(I2C0));
    value = (U8)i2c_get_data(I2C0);
    return value;
}

 
//在AT24CXX指定地址写入一个字节的数据
//WriteAddr  :写入数据的目的地址    
//DataToWrite:要写入的数据
void AT24CXX_WriteOneByte(U16 WriteAddr,U8 DataToWrite)
{
    if(WriteAddr>EE_TYPE)//数据范围检测
        return;

    // Write data into EEPROM
    // Send Control Byte
    i2c_send_data(I2C0, 0xA0); // Control Byte: 0xA0
    i2c_send_command(I2C0, I2C_START_WRITE); //do a start bit and send data
    if(!i2c_get_ack(I2C0)) {
        printf("No ack received from EEPROM, Device Control, Write data\n");
        return;
    }

    if(EE_TYPE>AT24C16)
	{
        // Send Write Address High
        i2c_send_data(I2C0, (int)(WriteAddr>>8)); // Write Addr High
        i2c_send_command(I2C0, I2C_WRITE); //do a start bit and send data
        if(!i2c_get_ack(I2C0)) {
            printf("No ack received from EEPROM, Address High\n");
            return;
        }
    }

    // Send Write Address Low
    i2c_send_data(I2C0, (int)(WriteAddr&0xff)); // Write Addr Low
    i2c_send_command(I2C0, I2C_WRITE); //do a start bit and send data
    if(!i2c_get_ack(I2C0)) {
        printf("No ack received from EEPROM, Address Low\n");
        return;
    }

    // Send Write Data
    i2c_send_data(I2C0, (int)DataToWrite);            //write i-th byte into fifo
    i2c_send_command(I2C0, I2C_WRITE); //send data on the i2c bus
    i2c_get_ack(I2C0);                 //wait for ack

    i2c_send_command(I2C0, I2C_STOP);      //do a stop bit, initiate eeprom write
    while(i2c_busy(I2C0));

    // 仿真时无需加延迟，FPGA实测时需要该延迟以等待AT24CXX完成写入
    if(~simu_flag){
        delay_ms(10);
    }
}


//在AT24CXX里面的指定地址开始写入长度为Len的数据
//该函数用于写入16bit或者32bit的数据.
//WriteAddr  :开始写入的地址  
//DataToWrite:数据数组首地址
//Len        :要写入数据的长度2,4（字节）
void AT24CXX_WriteLenByte(U16 WriteAddr,U32 DataToWrite,U8 Len)
{
	U8 t;

    if((WriteAddr+Len)>EE_TYPE)//数据范围检测
        return;
    
	for(t=0;t<Len;t++)
	{
		AT24CXX_WriteOneByte(WriteAddr+t,(DataToWrite>>(8*t))&0xff);
	}												    
}
 
 
//在AT24CXX里面的指定地址开始读出长度为Len的数据
//该函数用于读出16bit或者32bit的数据.
//ReadAddr   :开始读出的地址 
//返回值     :数据
//Len        :要读出数据的长度2,4（字节）
U32 AT24CXX_ReadLenByte(U16 ReadAddr,U8 Len)
{
	U8 t;
	U32 temp=0;

    if((ReadAddr+Len)>EE_TYPE)//数据范围检测
        return 0;

	for(t=0;t<Len;t++)
	{
		temp<<=8;
		temp+=AT24CXX_ReadOneByte(ReadAddr+Len-t-1); 	 				   
	}
	return temp;												    
}


//在AT24CXX里面的指定地址开始读出指定个数的数据
//ReadAddr :开始读出的地址 对24c02为0~255
//pBuffer  :数据数组首地址
//NumToRead:要读出数据的个数（字节）
void AT24CXX_Read(U16 ReadAddr,U8 *pBuffer,U16 NumToRead)
{
    if((ReadAddr+NumToRead)>EE_TYPE)//数据范围检测
        return;
    
	while(NumToRead)
	{
		*pBuffer++=AT24CXX_ReadOneByte(ReadAddr++);	
		NumToRead--;
	}
}
 
 
//在AT24CXX里面的指定地址开始写入指定个数的数据
//WriteAddr :开始写入的地址 对24c02为0~255
//pBuffer   :数据数组首地址
//NumToWrite:要写入数据的个数（字节）
void AT24CXX_Write(U16 WriteAddr,U8 *pBuffer,U16 NumToWrite)
{
    if((WriteAddr+NumToWrite)>EE_TYPE)//数据范围检测
        return;

	while(NumToWrite--)
	{
		AT24CXX_WriteOneByte(WriteAddr,*pBuffer);
		WriteAddr++;
		pBuffer++;
	}
}
